package com.voe;

import com.voe.callback.VoERTCPObserver;
import com.voe.callback.VoERTPObserver;
import com.voe.common.CallStatistics;
import com.voe.common.OutputParam;
import com.voe.common.RTPDirections;
import com.voe.common.ReportBlock;
import com.voe.common.ReturnValue;
import com.voe.common.SenderInfo;
import com.voe.common.Utility;

/**This sub-API supports the following functionalities:<br/>
*<br/>
*- Callbacks for RTP and RTCP events such as modified SSRC or CSRC.<br/>
*- SSRC handling.<br/>
*- Transmission of RTCP sender reports.<br/>
*- Obtaining RTCP data from incoming RTCP sender reports.<br/>
*- RTP and RTCP statistics (jitter, packet loss, RTT etc.).<br/>
*- Forward Error Correction (FEC).<br/>
*- Writing RTP and RTCP packets to binary files for off-line analysis of<br/>
* the call quality.<br/>
*- Inserting extra RTP packets into active audio stream.<br/>
*<br/>
*Usage example, omitting error checking:<br/>
*<br/>
*VoiceEngine voe = VoiceEngine.createInterface();<br/>
*VoEBase base = VoEBase.createInterface(voe);<br/>
*VoERTP_RTCP rtp_rtcp  = VoERTP_RTCP.createInterface(voe);<br/>
*base.init();<br/>
*int ch = base.createChannel();<br/>
*...<br/>
*rtp_rtcp.setLocalSSRC(ch, 12345);<br/>
*...<br/>
*base.deleteChannel(ch);<br/>
*base.terminate();<br/>
*base.release();<br/>
*rtp_rtcp.release();<br/>
*voe.release();<br/>
*/
public class VoERTP_RTCP {

	// [start] apis
	
	public static VoERTP_RTCP createInstance(VoiceEngine voiceEngine) {

		long p = GetInterface(voiceEngine._p);
		if(p != 0)
			return new VoERTP_RTCP(p);
		return null;
	}

	public void release() {
		if (_p != 0) {
			Release(_p);
		}
	}
	
	/** Registers an instance of a VoERTPObserver derived class for a specified<br/>
	 *  |channel|. It will allow the user to observe callbacks related to the<br/>
	 *  RTP protocol such as changes in the incoming SSRC.
	 */
	public int registerRTPObserver(int channel, VoERTPObserver observer) {
		Utility.throwNullPointerException(observer, "observer");
		return RegisterRTPObserver(_p, channel, observer);
	}

	/** Deregisters an instance of a VoERTPObserver derived class for a<br/>
	 *  specified |channel|.
	 */
	public int deRegisterRTPObserver(int channel) {
		return DeRegisterRTPObserver(_p, channel);
	}

	/** Registers an instance of a VoERTCPObserver derived class for a specified<br/>
	 *  |channel|.
	 */
	public int registerRTCPObserver(int channel, VoERTCPObserver observer) {
		Utility.throwNullPointerException(observer, "observer");
		return RegisterRTCPObserver(_p, channel, observer);
	}

	/** Deregisters an instance of a VoERTCPObserver derived class for a<br/>
	 *  specified |channel|.
	 */
	public int deRegisterRTCPObserver(int channel) {
		return DeRegisterRTCPObserver(_p, channel);
	}

	/** Sets the local RTP synchronization source identifier (SSRC) explicitly.
	 */
	public int setLocalSSRC(int channel, int ssrc) {
		return SetLocalSSRC(_p, channel, ssrc);
	}

	/** Gets the local RTP SSRC of a specified |channel|.
	 */
	public int getLocalSSRC(int channel, ReturnValue<Integer> ssrc) {
		OutputParam output = new OutputParam();
		int result = GetLocalSSRC(_p, channel, output);
		if(result == 0) {
			ssrc.setValue((Integer)output.getObject()[0]);
		}
		return result;
	}

	/** Gets the SSRC of the incoming RTP packets.
	 */
	public int getRemoteSSRC(int channel, ReturnValue<Integer> ssrc) {
		OutputParam output = new OutputParam();
		int result = GetRemoteSSRC(_p, channel, output);
		if(result == 0) {
			ssrc.setValue((Integer)output.getObject()[0]);
		}
		return result;
	}

	/** Sets the status of rtp-audio-level-indication on a specific |channel|.
	 */
	public int setRTPAudioLevelIndicationStatus(int channel, boolean enable, char ID) {
		return SetRTPAudioLevelIndicationStatus(_p, channel, enable, ID);
	}

	/** Sets the status of rtp-audio-level-indication on a specific |channel|.
	 */
	public int setRTPAudioLevelIndicationStatus(int channel, boolean enable) {
		return setRTPAudioLevelIndicationStatus(channel, enable, (char)1);
	}

	/** Sets the status of rtp-audio-level-indication on a specific |channel|.
	 */
	public int getRTPAudioLevelIndicationStatus(int channel, 
			ReturnValue<Boolean> enabled,
			ReturnValue<Byte> ID) {
		OutputParam output = new OutputParam();
		int result = GetRemoteSSRC(_p, channel, output);
		if(result == 0) {
			enabled.setValue((Boolean)output.getObject()[0]);
			ID.setValue(((Integer)output.getObject()[1]).byteValue());
		}
		return result;
	}

	/** Gets the CSRCs of the incoming RTP packets.
	 */
	public int getRemoteCSRCs(int channel, ReturnValue<int[]> arrCSRC) {
		OutputParam output = new OutputParam();
		int result = GetRemoteCSRCs(_p, channel, output);
		if(result == 0) {
			arrCSRC.setValue((int[])output.getObject()[0]);
		}
		return result;
	}

	/** Sets the RTCP status on a specific |channel|.
	 */
	public int setRTCPStatus(int channel, boolean enable) {
		return SetRTCPStatus(_p, channel, enable);
	}

	/** Gets the RTCP status on a specific |channel|.
	 */
	public int getRTCPStatus(int channel, ReturnValue<Boolean> enabled) {
		OutputParam output = new OutputParam();
		int result = GetRTCPStatus(_p, channel, output);
		if(result == 0) {
			enabled.setValue((Boolean)output.getObject()[0]);
		}
		return result;
	}

	/** Sets the canonical name (CNAME) parameter for RTCP reports on a<br/>
	 *  specific |channel|.
	 */
	public int setRTCP_CNAME(int channel, String cName) {
		return SetRTCP_CNAME(_p, channel, cName);
	}

	/** Gets the canonical name (CNAME) parameter for RTCP reports on a<br/>
	 *  specific |channel|.
	 */
	public int getRTCP_CNAME(int channel, ReturnValue<String> cName) {
		OutputParam output = new OutputParam();
		int result = GetRTCP_CNAME(_p, channel, output);
		if(result == 0) {
			cName.setValue((String)output.getObject()[0]);
		}
		return result;
	}

	/** Gets the canonical name (CNAME) parameter for incoming RTCP reports<br/>
	 *  on a specific channel.
	 */
	public int getRemoteRTCP_CNAME(int channel, ReturnValue<String> cName) {
		OutputParam output = new OutputParam();
		int result = GetRemoteRTCP_CNAME(_p, channel, output);
		if(result == 0) {
			cName.setValue((String)output.getObject()[0]);
		}
		return result;
	}

	/** Gets RTCP data from incoming RTCP Sender Reports.
	 */
	public int getRemoteRTCPData(int channel, 
			ReturnValue<Integer> NTPHigh,
			ReturnValue<Integer> NTPLow,
			ReturnValue<Integer> timestamp,
			ReturnValue<Integer> playoutTimestamp,
			ReturnValue<Integer> jitter,
			ReturnValue<Short> fractionLost) {
		OutputParam output = new OutputParam();
		int result = GetRemoteRTCPData(_p, channel, output);
		if(result == 0) {
			NTPHigh.setValue((Integer)output.getObject()[0]);
			NTPLow.setValue((Integer)output.getObject()[1]);
			timestamp.setValue((Integer)output.getObject()[2]);
			playoutTimestamp.setValue((Integer)output.getObject()[3]);
			if(jitter != null)
				jitter.setValue((Integer)output.getObject()[4]);
			if(fractionLost != null)
				fractionLost.setValue((Short)output.getObject()[5]);
		}
		return result;
	}

	/** Gets RTCP data from incoming RTCP Sender Reports.
	 */
	public int getRemoteRTCPData(int channel, 
			ReturnValue<Integer> NTPHigh,
			ReturnValue<Integer> NTPLow,
			ReturnValue<Integer> timestamp,
			ReturnValue<Integer> playoutTimestamp) {
		return getRemoteRTCPData(channel, NTPHigh, NTPLow,
				timestamp, playoutTimestamp, null, null);
	}

	/** Gets RTP statistics for a specific |channel|.
	 */
	public int getRTPStatistics(int channel,
			ReturnValue<Integer> averageJitterMs,
			ReturnValue<Integer> maxJitterMs,
			ReturnValue<Integer> discardedPackets) {
		OutputParam output = new OutputParam();
		int result = GetRTPStatistics(_p, channel, output);
		if(result == 0) {
			averageJitterMs.setValue((Integer)output.getObject()[0]);
			maxJitterMs.setValue((Integer)output.getObject()[1]);
			discardedPackets.setValue((Integer)output.getObject()[2]);
		}
		return result;
	}

	/** Gets RTCP statistics for a specific |channel|.
	 */
	public int getRTCPStatistics(int channel, ReturnValue<CallStatistics> stats) {
		OutputParam output = new OutputParam();
		int result = GetRTCPStatistics(_p, channel, output);
		if(result == 0) {
			CallStatistics tmp = new CallStatistics();
			tmp.fractionLost = (Short)output.getObject()[0];
			tmp.cumulativeLost = (Integer)output.getObject()[1];
			tmp.extendedMax = (Integer)output.getObject()[2];
			tmp.jitterSamples = (Integer)output.getObject()[3];
			tmp.rttMs = (Integer)output.getObject()[4];
			tmp.bytesSent = (Integer)output.getObject()[5];
			tmp.packetsSent = (Integer)output.getObject()[6];
			tmp.bytesReceived = (Integer)output.getObject()[7];
			tmp.packetsReceived = (Integer)output.getObject()[8];
			stats.setValue(tmp);
		}
		return result;
	}

	/** Gets the sender info part of the last received RTCP Sender Report (SR)<br/>
	 *  on a specified |channel|.
	 */
	public int getRemoteRTCPSenderInfo(int channel, ReturnValue<SenderInfo> sender_info) {
		OutputParam output = new OutputParam();
		int result = GetRemoteRTCPSenderInfo(_p, channel, output);
		if(result == 0) {
			SenderInfo tmp = new SenderInfo();
			tmp.NTP_timestamp_high = (Integer)output.getObject()[0];
			tmp.NTP_timestamp_low = (Integer)output.getObject()[1];
			tmp.RTP_timestamp = (Integer)output.getObject()[2];
			tmp.sender_packet_count = (Integer)output.getObject()[3];
			tmp.sender_octet_count = (Integer)output.getObject()[4];
			sender_info.setValue(tmp);
		}
		return result;
	}

	/** Gets the report block parts of the last received RTCP Sender Report (SR),<br/>
	 *  or RTCP Receiver Report (RR) on a specified |channel|. Each vector<br/>
	 *  element also contains the SSRC of the sender in addition to a report<br/>
	 *  block.
	 */
	public int getRemoteRTCPReportBlocks(int channel, ReturnValue<ReportBlock[]> receive_blocks) {
		OutputParam output = new OutputParam();
		int result = GetRemoteRTCPSenderInfo(_p, channel, output);
		if(result == 0) {
			ReportBlock[] tmp = new ReportBlock[output.getObject().length];
			for(int i=0;i<tmp.length;i++) {
				OutputParam param = (OutputParam) output.getObject()[i];
				ReportBlock rb = tmp[i];
				rb.sender_SSRC = (Integer) param.getObject()[0];
				rb.source_SSRC = (Integer) param.getObject()[1];
				rb.fraction_lost = (Integer) param.getObject()[2];
				rb.cumulative_num_packets_lost = (Integer) param.getObject()[3];
				rb.extended_highest_sequence_number = (Integer) param.getObject()[4];
				rb.interarrival_jitter = (Integer) param.getObject()[5];
				rb.last_SR_timestamp = (Integer) param.getObject()[6];
				rb.delay_since_last_SR = (Integer) param.getObject()[7];
			}
			receive_blocks.setValue(tmp);
		}
		return result;
	}

	/** Sends an RTCP APP packet on a specific |channel|.
	 */
	public int sendApplicationDefinedRTCPPacket(int channel, 
			char subType, int name, byte[] data) {
		return SendApplicationDefinedRTCPPacket(_p, channel, subType, name, data);
	}

	/** Sets the Forward Error Correction (FEC) status on a specific |channel|.
	 */
	public int setFECStatus(int channel, boolean enable, int redPayloadtype) {
		return SetFECStatus(_p, channel, enable, redPayloadtype);
	}

	/** Sets the Forward Error Correction (FEC) status on a specific |channel|.
	 */
	public int setFECStatus(int channel, boolean enable) {
		return setFECStatus(channel, enable, -1);
	}

	/** Gets the FEC status on a specific |channel|.
	 */
	public int getFECStatus(int channel, 
			ReturnValue<Boolean> enabled, 
			ReturnValue<Integer> redPayloadtype) {
		OutputParam output = new OutputParam();
		int result = GetFECStatus(_p, channel, output);
		if(result == 0) {
			enabled.setValue((Boolean)output.getObject()[0]);
			redPayloadtype.setValue((Integer)output.getObject()[1]);
		}
		return result;
	}

	/** Enables capturing of RTP packets to a binary file on a specific<br/>
	 *  |channel| and for a given |direction|. The file can later be replayed<br/>
	 *  using e.g. RTP Tools rtpplay since the binary file format is<br/>
	 *  compatible with the rtpdump format.
	 */
	public int startRTPDump(int channel, String fileNameUTF8, RTPDirections direction) {
		return StartRTPDump(_p, channel, fileNameUTF8, direction.getValue());
	}

	/** Enables capturing of RTP packets to a binary file on a specific<br/>
	 *  |channel| and for a given |direction|. The file can later be replayed<br/>
	 *  using e.g. RTP Tools rtpplay since the binary file format is<br/>
	 *  compatible with the rtpdump format.
	 */
	public int startRTPDump(int channel, String fileNameUTF8) {
		return startRTPDump(channel, fileNameUTF8, RTPDirections.kRtpIncoming);
	}

	/** Disables capturing of RTP packets to a binary file on a specific<br/>
	 *  |channel| and for a given |direction|.
	 */
	public int stopRTPDump(int channel, RTPDirections direction) {
		return StopRTPDump(_p, channel, direction.getValue());
	}

	/** Disables capturing of RTP packets to a binary file on a specific<br/>
	 *  |channel| and for a given |direction|.
	 */
	public int stopRTPDump(int channel) {
		return stopRTPDump(channel, RTPDirections.kRtpIncoming);
	}

	/** Gets the the current RTP capturing state for the specified<br/>
	 *  |channel| and |direction|.
	 */
	public int rtpDumpIsActive(int channel, RTPDirections direction) {
		return RTPDumpIsActive(_p, channel, direction.getValue());
	}

	/** Gets the the current RTP capturing state for the specified<br/>
	 *  |channel| and |direction|.
	 */
	public int rtpDumpIsActive(int channel) {
		return rtpDumpIsActive(channel, RTPDirections.kRtpIncoming);
	}

	/** Sends an extra RTP packet using an existing/active RTP session.<br/>
	 *  It is possible to set the payload type, marker bit and payload<br/>
	 *  of the extra RTP
	 */
	public int insertExtraRTPPacket(int channel, char payloadType, 
			boolean markerBit, byte[] payload) {
		return InsertExtraRTPPacket(_p, channel, payloadType, markerBit, payload);
	}

	/** Gets the timestamp of the last RTP packet received by |channel|.
	 */
	public int getLastRemoteTimeStamp(int channel, 
			ReturnValue<Integer> lastRemoteTimeStamp) {
		OutputParam output = new OutputParam();
		int result = GetLastRemoteTimeStamp(_p, channel, output);
		if(result == 0) {
			lastRemoteTimeStamp.setValue((Integer)output.getObject()[0]);
		}
		return result;
	}

	protected VoERTP_RTCP(long p) {
		_p = p;
	}

	protected long _p;
	
	// [end]
	
	
	
	

	// [start] jni api

	// Factory for the VoERTP_RTCP sub-API. Increases an internal
	// reference counter if successful. Returns NULL if the API is not
	// supported or if construction fails.
	private static native long GetInterface(long p_voiceEngine);

	// Releases the VoERTP_RTCP sub-API and decreases an internal
	// reference counter. Returns the new reference count. This value should
	// be zero for all sub-API:s before the VoiceEngine object can be safely
	// deleted.
	private static native int Release(long p_VoERTP_RTCP);

	// Registers an instance of a VoERTPObserver derived class for a specified
	// |channel|. It will allow the user to observe callbacks related to the
	// RTP protocol such as changes in the incoming SSRC.
	private static native int RegisterRTPObserver(long p_VoERTP_RTCP,
			int channel, VoERTPObserver observer);

	// Deregisters an instance of a VoERTPObserver derived class for a
	// specified |channel|.
	private static native int DeRegisterRTPObserver(long p_VoERTP_RTCP,
			int channel);

	// Registers an instance of a VoERTCPObserver derived class for a specified
	// |channel|.
	private static native int RegisterRTCPObserver(long p_VoERTP_RTCP,
			int channel, VoERTCPObserver observer);

	// Deregisters an instance of a VoERTCPObserver derived class for a
	// specified |channel|.
	private static native int DeRegisterRTCPObserver(long p_VoERTP_RTCP,
			int channel);

	// Sets the local RTP synchronization source identifier (SSRC) explicitly.
	private static native int SetLocalSSRC(long p_VoERTP_RTCP, int channel,
			int ssrc);

	// Gets the local RTP SSRC of a specified |channel|.
	private static native int GetLocalSSRC(long p_VoERTP_RTCP, int channel,
			OutputParam ssrc);

	// Gets the SSRC of the incoming RTP packets.
	private static native int GetRemoteSSRC(long p_VoERTP_RTCP, int channel,
			OutputParam ssrc);

	// Sets the status of rtp-audio-level-indication on a specific |channel|.
	private static native int SetRTPAudioLevelIndicationStatus(
			long p_VoERTP_RTCP, int channel, boolean enable, char ID);

	// Sets the status of rtp-audio-level-indication on a specific |channel|.
	private static native int GetRTPAudioLevelIndicationStatus(
			long p_VoERTP_RTCP, int channel, OutputParam param);

	// Gets the CSRCs of the incoming RTP packets.
	private static native int GetRemoteCSRCs(long p_VoERTP_RTCP, int channel,
			OutputParam arrCSRC);

	// Sets the RTCP status on a specific |channel|.
	private static native int SetRTCPStatus(long p_VoERTP_RTCP, int channel,
			boolean enable);

	// Gets the RTCP status on a specific |channel|.
	private static native int GetRTCPStatus(long p_VoERTP_RTCP, int channel,
			OutputParam enabled);

	// Sets the canonical name (CNAME) parameter for RTCP reports on a
	// specific |channel|.
	private static native int SetRTCP_CNAME(long p_VoERTP_RTCP, int channel,
			String cName);

	// Gets the canonical name (CNAME) parameter for RTCP reports on a
	// specific |channel|.
	private static native int GetRTCP_CNAME(long p_VoERTP_RTCP, int channel,
			OutputParam cName);

	// Gets the canonical name (CNAME) parameter for incoming RTCP reports
	// on a specific channel.
	private static native int GetRemoteRTCP_CNAME(long p_VoERTP_RTCP,
			int channel, OutputParam cName);

	// Gets RTCP data from incoming RTCP Sender Reports.
	private static native int GetRemoteRTCPData(long p_VoERTP_RTCP,
			int channel, OutputParam param);

	// Gets RTP statistics for a specific |channel|.
	private static native int GetRTPStatistics(long p_VoERTP_RTCP, int channel,
			OutputParam discardedPackets);

	// Gets RTCP statistics for a specific |channel|.
	private static native int GetRTCPStatistics(long p_VoERTP_RTCP,
			int channel, OutputParam stats);

	// Gets the sender info part of the last received RTCP Sender Report (SR)
	// on a specified |channel|.
	private static native int GetRemoteRTCPSenderInfo(long p_VoERTP_RTCP,
			int channel, OutputParam sender_info);

	// Gets the report block parts of the last received RTCP Sender Report (SR),
	// or RTCP Receiver Report (RR) on a specified |channel|. Each vector
	// element also contains the SSRC of the sender in addition to a report
	// block.
	private static native int GetRemoteRTCPReportBlocks(long p_VoERTP_RTCP,
			int channel, OutputParam receive_blocks);

	// Sends an RTCP APP packet on a specific |channel|.
	private static native int SendApplicationDefinedRTCPPacket(
			long p_VoERTP_RTCP, int channel, char subType, int name, byte[] data);

	// Sets the Forward Error Correction (FEC) status on a specific |channel|.
	private static native int SetFECStatus(long p_VoERTP_RTCP, int channel,
			boolean enable, int redPayloadtype);

	// Gets the FEC status on a specific |channel|.
	private static native int GetFECStatus(long p_VoERTP_RTCP, int channel,
			OutputParam param);

	// Enables capturing of RTP packets to a binary file on a specific
	// |channel| and for a given |direction|. The file can later be replayed
	// using e.g. RTP Tools rtpplay since the binary file format is
	// compatible with the rtpdump format.
	private static native int StartRTPDump(long p_VoERTP_RTCP, int channel,
			String fileNameUTF8, int direction);

	// Disables capturing of RTP packets to a binary file on a specific
	// |channel| and for a given |direction|.
	private static native int StopRTPDump(long p_VoERTP_RTCP, int channel,
			int direction);

	// Gets the the current RTP capturing state for the specified
	// |channel| and |direction|.
	private static native int RTPDumpIsActive(long p_VoERTP_RTCP, int channel,
			int direction);

	// Sends an extra RTP packet using an existing/active RTP session.
	// It is possible to set the payload type, marker bit and payload
	// of the extra RTP
	private static native int InsertExtraRTPPacket(long p_VoERTP_RTCP,
			int channel, char payloadType, boolean markerBit, byte[] payload);

	// Gets the timestamp of the last RTP packet received by |channel|.
	private static native int GetLastRemoteTimeStamp(long p_VoERTP_RTCP,
			int channel, OutputParam lastRemoteTimeStamp);

	// [end]
}
